package com.makemoney.miniprogram.modules.users.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.makemoney.miniprogram.modules.users.dao.IResourcesDao;
import com.makemoney.miniprogram.modules.users.dao.IRoleResourceDao;
import com.makemoney.miniprogram.modules.users.entity.Resources;
import com.makemoney.miniprogram.modules.users.service.IResourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ResourceServiceImpl implements IResourceService {

    @Resource
    private IResourcesDao resourcesDao;
    @Resource
    private IRoleResourceDao roleResourceDao;

    @Value("${server.port}")
    private String port;
    @Value("${springdoc.api-docs.path}")
    private String apiDocPath;

    @Override
    public String update() {
        String apiDocUrl = "localhost:" + port + apiDocPath;
        String jsonStr = HttpUtil.get(apiDocUrl);
        if (StrUtil.isEmpty(jsonStr)) {
            return "未获取到api-doc";
        }
        JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
        if (!jsonObject.keySet().contains("paths")) {
            return "未找到paths";
        }
        JSONObject paths = jsonObject.get("paths", JSONObject.class);
        List<Resources> resourcesList = resourcesDao.listAll();
        List<Resources> addList = new ArrayList<>();
        List<Resources> updateList = new ArrayList<>();
        Set<String> existsSet = new HashSet<>();
        for (String jsonKey : paths.keySet()) {
            JSONObject jsonPath = paths.get(jsonKey, JSONObject.class);
            String parentKey = this.getParentKey(jsonKey);
            existsSet.add(parentKey);
            Long parentId = 0L;
            if (!resourcesList.stream().anyMatch(r -> parentKey.equals(r.getResourceKey()))
                    && !addList.stream().anyMatch(r -> parentKey.equals(r.getResourceKey()))) {
                Resources parentEntity = new Resources();
                parentEntity.setId(IdWorker.getId());
                this.setResourcesEntity(parentEntity, 0L, 0, jsonPath,
                        StrUtil.SLASH + parentKey, parentKey, addList);
                parentId = parentEntity.getId();
            } else {
                parentId = this.getResourcesParentId(parentKey, resourcesList, addList);
            }
            String key = this.transKey(jsonKey);
            existsSet.add(key);
            Optional<Resources> resourcesOptional = resourcesList.stream().filter(r -> key.equals(r.getResourceKey()))
                    .findAny();

            if (resourcesOptional.isPresent()) {
                // 修改
                Resources updateEntity = resourcesOptional.get();
                this.setResourcesEntity(updateEntity, parentId, 1, jsonPath, jsonKey, key, updateList);
            } else {
                // 新增
                Resources addEntity = new Resources();
                addEntity.setId(IdWorker.getId());
                this.setResourcesEntity(addEntity, parentId, 1, jsonPath, jsonKey, key, addList);
            }
        }
        List<Long> removeIdList = resourcesList.stream().filter(r -> !existsSet.contains(r.getResourceKey()))
                .map(r -> r.getId()).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(addList)) {
            resourcesDao.addList(addList);
        }
        if(CollUtil.isNotEmpty(updateList)) {
            resourcesDao.updateList(updateList);
        }
        if(CollUtil.isNotEmpty(removeIdList)) {
            resourcesDao.removeByIdList(removeIdList);
            roleResourceDao.removeByResourcesIdList(removeIdList);
        }
        String result = "新增：" + addList.size() + "条;" +
                "修改：" + updateList.size() + "条;" +
                "删除" + removeIdList.size() + "条.";
        return result;
    }

    //region
    private String transKey(String jsonKey) {
        String key = StrUtil.replace(
                StrUtil.removePrefix(jsonKey, StrUtil.SLASH),
                StrUtil.SLASH, StrUtil.DASHED);
        if (key.endsWith(StrUtil.DASHED)) {
            key = StrUtil.subBefore(key, StrUtil.DASHED, Boolean.TRUE);
        }
        return key;
    }

    private String getParentKey(String jsonKey) {
        return StrUtil.split(jsonKey, StrUtil.SLASH, Boolean.TRUE, Boolean.TRUE).get(0);
    }

    private Long getResourcesParentId(String key, List<Resources> existsList,
                                      List<Resources> addList) {
        Optional<Resources> resourcesOptional = existsList.stream().filter(r -> r.getResourceKey().equals(key))
                .findFirst();
        if (resourcesOptional.isPresent()) {
            return resourcesOptional.get().getId();
        }
        resourcesOptional = addList.stream().filter(r -> r.getResourceKey().equals(key))
                .findFirst();
        if (resourcesOptional.isPresent()) {
            return resourcesOptional.get().getId();
        }
        return null;
    }

    private void setResourcesEntity(Resources entity, Long parentId,
                                    Integer leaf, JSONObject jsonPath,
                                    String url, String key, List<Resources> list) {
        String method = jsonPath.keySet().iterator().next();
        JSONObject entries = jsonPath.get(method, JSONObject.class);
        entity.setResourceKey(key);
        entity.setResourceUrl(url);
        entity.setLeaf(leaf);
        if (1 == leaf) {
            entity.setResourceName(entries.get("summary", String.class));
        } else {
            List<String> tags = entries.getBeanList("tags", String.class);
            if (CollUtil.isNotEmpty(tags)) {
                entity.setResourceName(tags.get(0));
            }
        }
        entity.setParentId(parentId);
        entity.setMethods(method);
        entity.setResourceType(1);
        list.add(entity);
    }
    //endregion
}
